package com.chalk.config.security;

import com.chalk.common.constant.CommonConstants;
import com.chalk.common.constant.SecurityConstants;
import com.chalk.model.SysUser;
import com.chalk.service.SysPermissionService;
import com.chalk.vo.SysPermissionVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * ClassName: CustomInvocationSecurityMetadataSourceService
 *
 * @author L.G
 * @Description 自定义 FilterInvocationSecurityMetadataSource
 * @email lg10000@126.com
 * @date 2018年8月27日 下午4:20:50
 */
@Component
public class CustomInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {

    private HashMap<String, Collection<ConfigAttribute>> permissionsMap = null;

    @Autowired
    private SysPermissionService permissionService;

    /**
     * 加载权限
     */
    public void loadAllPermissions() {
        permissionsMap = new HashMap<>();
        /* 查询平台全部菜单 */
        Map<Object, Object> params = new HashMap<>();
        /* 查询平台全部菜单 */
        params.put("permType", 1);
        params.put("isDelete", CommonConstants.IsDeleted.NOTDEL.getValue());
        List<SysPermissionVo> menuList = permissionService.selectMenus(params);
        if (menuList != null && menuList.size() > 0) {
            menuList.forEach(menu -> {
                ConfigAttribute cfg = new SecurityConfig(menu.getPermission());
                Collection<ConfigAttribute> array = new ArrayList<>();
                array.add(cfg);
                /* 用权限的getUrl()作为map的key，用ConfigAttribute的集合作为 value */
                permissionsMap.put(menu.getPermResource(), array);
            });
        }
        /* 用户信息接口只需登录权限 */
        ConfigAttribute cfg = new SecurityConfig(SecurityConstants.ROLE_LOGIN);
        Collection<ConfigAttribute> array = new ArrayList<>();
        array.add(cfg);
        permissionsMap.put("/v1/sysUser/**", array);
    }

    /**
     * 此方法是为了判定用户请求的url是否在权限表中，如果在权限表中，则返回给 decide 方法，用来判定用户是否有此权限。如果不在权限表中则放行。
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        /* object中包含用户请求的request信息 */
        HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
        System.out.println("--------------------------------" + request.getRequestURI());
        /**
         * 判断用户状态是否正常
         */
        /* 获取操作用户 */
        SysUser sysUser = (SysUser) UserDetailsUtil.getUserInfo("sysUserService", "user_name");
        /* 是否删除 */
        if (sysUser != null && sysUser.getIsDelete().equals(CommonConstants.IsDeleted.DEL.getValue())) {
            String token = SpringContextUtil.extractHeaderToken(request);
            throw new AccessDeniedException("用户已删除");
        }
        if (permissionsMap == null) {
            /*重新获取数据库中权限*/
            loadAllPermissions();
        }
        AntPathRequestMatcher matcher;
        String resUrl;
        for (Iterator<String> iter = permissionsMap.keySet().iterator(); iter.hasNext(); ) {
            resUrl = iter.next();
            matcher = new AntPathRequestMatcher(resUrl);
            if (matcher.matches(request)) {
                return permissionsMap.get(resUrl);
            }
        }

        /*List<ConfigAttribute> list = new ArrayList<>(1);
        list.add(new SecurityConfig(SecurityConstants.ERROR_LOGIN));
        return list;*/
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

}